package com.lw.lwte.autoapi.http;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.lw.lwte.common.enums.HttpMethod;
import com.lw.lwte.common.enums.MediaType;
import com.lw.lwte.common.helper.StringHelper;
import org.testng.Reporter;

import java.net.HttpCookie;
import java.util.HashMap;
import java.util.Map;

/**
 * @author liuwei
 * @date 2024/10/30
 * @description: http请求
 */
public class ApiRequest {
    private String url;
    private Map<String, String> params = new HashMap<>();
    private Map<String, String> headers = new HashMap<>();
    private Map<String, String> cookies = new HashMap<>();

    private MediaType contentType = MediaType.APPLICATION_JSON;
    private MediaType acceptType = MediaType.ALL_TYPES;
    private String httpMethod;

    private String body;

    public Map<String, String> getParams() {
        return params;
    }

    public Map<String, String> getHeaders() {
        return headers;
    }

    public Map<String, String> getCookies() {
        return cookies;
    }

    public MediaType getContentType() {
        return contentType;
    }

    public MediaType getAcceptType() {
        return acceptType;
    }

    public String getHttpMethod() {
        return httpMethod;
    }

    public String getBody() {
        return body;
    }

    public String getUrl() {
        return url;
    }

    private ApiRequest(String url, String method) {
        this.url = url;
        this.httpMethod = method;
    }

    private ApiRequest(String url, HttpMethod method) {
        this.url = url;
        this.httpMethod = method.toString();
    }

    public static ApiRequest GET(String uri) {
        return new ApiRequest(uri, HttpMethod.GET);
    }

    public static ApiRequest POST(String uri) {
        return new ApiRequest(uri, HttpMethod.POST);
    }

    public static ApiRequest PUT(String uri) {
        return new ApiRequest(uri, HttpMethod.PUT);
    }

    public static ApiRequest DELETE(String uri) {
        return new ApiRequest(uri, HttpMethod.DELETE);
    }

    public static ApiRequest HEAD(String uri) {
        return new ApiRequest(uri, HttpMethod.HEAD);
    }

    public ApiRequest path(String value) {
        if (value.contains("//")) {
            this.url = value;
        } else {
            this.url = this.url.concat(value);
        }
        return this;
    }

    public ApiRequest param(String key, String value) {
        this.params.put(key, value);
        return this;
    }

    public ApiRequest params(Map<String, String> params) {
        this.params = params;
        return this;
    }

    public ApiRequest cookies(Map<String, String> cookies) {
        this.cookies = cookies;
        return this;
    }

    public ApiRequest contentType(MediaType type) {
        this.contentType = type;
        return this;
    }

    public ApiRequest accept(MediaType type) {
        this.acceptType = type;
        return this;
    }

    public ApiRequest header(String key, String value) {
        key = StringHelper.firstUpper(key);
        for(String item : this.headers.keySet()){
            if(item.toLowerCase().equals(key.toLowerCase())){
                this.headers.put(item, value);
                return this;
            }
        }

        this.headers.put(key, value);
        return this;
    }

    public ApiRequest authBearerHeader(String token) {
        this.headers.put("Authorization", "Bearer " + token);
        return this;
    }

    public ApiRequest authTokenHeader(String type, String token) {
        this.headers.put("Authorization", type + " " + token);
        return this;
    }

    public ApiRequest headers(Map<String, String> headers) {
        this.headers = headers;
        return this;
    }

    public ApiRequest body(String body) {
        this.body = body;
        return this;
    }

    public ApiResponse invoke() {
        //设置URL
        HttpRequest request = new HttpRequest(url);

        //设置METHOD
        Method method = Method.valueOf(httpMethod);
        request.setMethod(method);

        //设置HEADERS
        if (!headers.keySet().contains("Content-Type")) {
            this.header("Content-Type", contentType.toString());
        }
        if (!headers.keySet().contains("Accept")) {
            this.header("Accept", acceptType.toString());
        }
        request.addHeaders(headers);

        //设置Cookie
        if (!cookies.isEmpty()) {
            for (String item : cookies.keySet()) {
                HttpCookie httpCookie = new HttpCookie(item, cookies.get(item));
                request.cookie(httpCookie);
            }
        }

        //设置PARAMETER todo: 此处默认get请求方式的contentType不可以是 application/json 后续酌情优化
        if (!params.isEmpty()) {
            if (contentType.equals(MediaType.APPLICATION_JSON)) {
                body = new Gson().toJson(params);
                request.body(body);
            } else {
                body = URLUtil.buildQuery(params, CharsetUtil.CHARSET_UTF_8);
                request.form((Map) params);
            }
        } else {
            //直接设置BODY
            if (!StringHelper.isNullOrBlank(body)) {
                request.body(body);
            }
        }

        //发送请求
        Reporter.log(getRequestInfo(), true);

        //请求执行并输出响应时间
        long start = System.currentTimeMillis();
        HttpResponse response = request.execute();
        long end = System.currentTimeMillis();
        Reporter.log(String.format("RequestAPI: %s, ResponseTime: %dms\n", url, end - start), true);

        //打印响应报文
        ApiResponse apiResponse = new ApiResponse(response);
        Reporter.log(apiResponse.getResponseInfo(), true);

        return apiResponse;
    }

    public String getRequestInfo() {
        StringBuilder stringBuilder = new StringBuilder();
        //METHOD + URL
        stringBuilder.append(String.format("%s %s\n", getHttpMethod(), getUrl()));

        //Headers
        if (headers.size() != 0) {
            stringBuilder.append("Headers:\n");
            for (String key : headers.keySet()) {
                stringBuilder.append(String.format("%s: %s\n", key, headers.get(key)));
            }
        }

        //Cookie
        if (!cookies.isEmpty()) {
            Map tempData = cookies;
            Map<String, Object> cookieMap = tempData;
            JSONObject json = new JSONObject(cookieMap);
            stringBuilder.append(String.format("Cookie: %s\n", json.toJSONString()));
        }

        //Parameter
        if (body != null) {
            stringBuilder.append("Parameter:\n").append(StringHelper.prettyFormat(body));
        }
        stringBuilder.append("\n");

        return stringBuilder.toString();
    }

}